<?php

/*
 * This is the game's main class
 */

class Game_Model extends Model {

    function __construct() {
        parent::__construct();

        if (isset($_SESSION ['flag'])) {
            // print_r($this->getPlayercardds());
            // echo $this->getPlayercardds();
        }


        //  print_r($this->gameStackReplenish((int) 1));
        // print_r($this->countsHandStack('opponentarray'));
        //print_r($this->lowesOpponentCard());
    }

    /*
     * play array 
     */

    private $playarray = array();

    /*
     * opponent array (PC)
     */
    private $opponentarray = array();

    /*
     * user array
     */
    private $userarray = array();
    private $action = "";
    private $attakerscard = "";
    /*
     * counter DB insert
     */
    private $fenrty = 0;

    /*
     * the master suit card
     */
    private $mastersuit = "";

    /*
     * game id from the DB
     */
    private $plid = 0;

    /**
     * This is the stack Array. The stack should be shuffled
     * v -11
     * d -12
     * k -13
     * A - 14
     * @param cardArray cardArray
     */
    private function stackArray() {
        $cardArray = array(
            "6 &spades",
            "6 &clubs",
            "6 &hearts",
            "6 &diams",
            "7 &spades",
            "7 &clubs",
            "7 &hearts",
            "7 &diams",
            "8 &spades",
            "8 &clubs",
            "8 &hearts",
            "8 &diams",
            "9 &spades",
            "9 &clubs",
            "9 &hearts",
            "9 &diams",
            "10 &spades",
            "10 &clubs",
            "10 &hearts",
            "10 &diams",
            "11 &spades",
            "11 &clubs",
            "11 &hearts",
            "11 &diams",
            "12 &spades",
            "12 &clubs",
            "12 &hearts",
            "12 &diams",
            "13 &spades",
            "13 &clubs",
            "13 &hearts",
            "13 &diams",
            "14 &spades",
            "14 &clubs",
            "14 &hearts",
            "14 &diams"
                )
        ;
        return $cardArray;
    }

    /**
     * This function is used once  - when  the game starts
     *
     * @param player, game_array, playarray, opponentarray, userarray,
     *        	gflag, action, mastersuit
     */
    private function dataInsert($player, $stack_array, $playarray, $opponentarray, $userarray, $gflag, $action, $mastersuit) {
        $sth = $this->db->prepare(' 
                    INSERT INTO game (player, stack_array, 
                        playarray, opponentarray, userarray, 
                        gflag, action, mastersuit) 
                     VALUES (
                        :player,
                        :stack_array,
                        :playarray,
                        :opponentarray,
                        :userarray,
                        :gflag,
                        :action,
                        :mastersuit
                      )
                  ');
        $sth->execute(array(
            ':player' => $player,
            ':stack_array' => $stack_array,
            ':playarray' => $playarray,
            ':opponentarray' => $opponentarray,
            ':userarray' => $userarray,
            ':gflag' => $gflag,
            ':action' => $action,
            ':mastersuit' => $mastersuit
        ));

        $data = array(
            'id' => $this->db->lastInsertId()
        );
        $_SESSION ['fenrty'] = 1;
    }

    /**
     * updates colums by game id 
     * if array 
     * else strings
     * @param strin $columnName
     * @param string $data should be formated well(\")
     * 
     */
    private function updateColums($columnName, $data) {
        $clname = "";
        $gameId = (int) $this->GetData("id", "");
        // will remove this function from all functions
        if (is_array($columnName)) {
            $clname = json_encode($columnName);
        } else {
            $clname = $columnName;
        }
        $sth = $this->db->prepare('
                        UPDATE `game`   

                        SET  ' . $columnName . '  =  "' . $data . '"  

                        WHERE `id` = "' . $gameId . '" 

    ');
        $sth->execute();
        // print_r($sth);
    }

    /*
     * generic function selects  one column  
     * q - column name,  
     * d - this function switch
     * "ar" returns array  
     * "" - returns string 
     * 
     * @param  string $q the column name
     * @param  string $d if "ar" will works with array, else with string 
     * @return mix array or string
     */

    private function GetData($q, $d) {
        // $some=$_POST['step'];
        $uname = $_SESSION ['username'];
        $sth = $this->db->prepare("SELECT `$q` FROM game 
            where player= :name");
        $sth->bindValue(':name', $uname);
        $sth->setFetchMode(PDO::FETCH_ASSOC);
        $sth->execute();
        if ($d === "ar") {
            $data = $sth->fetchAll();

            $udata = array();

            // returns unserialize($data[0]);
            foreach ($data as $user) {
                $udata = json_decode($user ["$q"]);
            }

            return $udata;
        } else {
            // returns string
            $qwe = "";
            $sth->bindColumn(1, $id);
            while ($sth->fetch(PDO::FETCH_BOUND)) {

                $qwe = $id;
            }

            return $qwe;
            // returns $result;;
        }
    }

    /*
     * starting
     */

    private function firstTimeRun() {
        // $_POST['gstat'];
        // 
        $check = $this->GetData("gflag", "");
        if (empty($check)) {
            if ($this->fenrty < 1 and $_SESSION ['fenrty'] < 1) {
                // shuffle the cardds
                $sharray = $this->stackArray();
                shuffle($sharray);
                $tork = $sharray;
                //each player takes 6 cards
                $first12 = $tork;
                $first12 = array_slice($first12, 0, 12);

                foreach ($first12 as $i => $q) {
                    if ($i % 2) {
                        $this->userarray [] = $q;
                    } else {
                        $this->opponentarray [] = $q;
                    }
                    // removes first 12 cards from the play array
                    unset($tork [$i]);
                }

                $tork = array_values($tork);
                $this->playarray = $tork;
                $mastersuitNs = array();

                //total cards 36
                // -12 cards for the first time
                // 24 -> 0 to 23 the last card will be [23]
                /* foreach ($tork as $k => $val) {
                  $mastersuitNs [23] = $val;
                  } */
                // $mastersuitNs = array_slice($tork, 0, 1); //array();
                // $this->mastersuit = $mastersuitNs;

                $mastersuit = end($tork);

                // DB preparation,converts array to the string
                $_SESSION ['gar'] = json_encode($tork);
                $playarray = json_encode($tork);
                $opponentarray = json_encode($this->opponentarray);
                // implode(',', $columnNames)
                $userarray = json_encode($this->userarray);
                $player = $_SESSION ['username'];
                $stack_array = json_encode($tork);
                $gflag = "";
                $action = "";
                $this->dataInsert($player, $stack_array, $playarray, $opponentarray, $userarray, $gflag, $action, $mastersuit);


                // echo ("inserted");
            }
        }
    }

    private function displayGameTable() {
        $userarray = $this->getPlayerCards();
        $this->fenrty = 1;
        // $cards = array_merge($userarray, $mastersuit);
        $this->plid = (int) $this->GetData("id", "");
        $opponentarray = $this->getOpponentCards();
        return json_encode($userarray);
    }

    /*
     * main game stack manipulations
     * updates new cards  to  player stack
     * updates self column minus ? cards
     * @param string $columnName
     * @param int $numb
     */

    private function gameStackReplenish($columnName, $numb) {
        $var = 0;
        if (is_int($numb)) {
            $var = $numb;
        } else {
            $var = (int) $numb;
        }

        $returnedarray = array();
        $newstask = array();
        $oldstack = (array) $this->GetData("stack_array", "ar");
        //Reset keys of array elements
        // $oldstack = array_values($oldstack);
        $newstask = $oldstack;
        foreach ($newstask as $i => $value) {

            if ($i <= $var) {
                unset($oldstack [$i]);

                $returnedarray[] = $value;
            }
        }

        //Resets keys of array elements and converts to json
        $oldstackstr = json_encode(array_values($oldstack));

        //removes key from json array
        $oldstackstr = $this->jsonFormated($oldstackstr);
        $this->updateColums('stack_array', $oldstackstr, "ar");
        //updata player stack
        $this->addHandStack($columnName, $returnedarray);
    }

    /*
     * counts quantity  cards on hand stack
     * update stack if needs
     * @param string $columnName
     */

    private function countsHandStack($columnName) {

        $handstack = $this->GetData($columnName, "ar");
        $qcards = 0;
        if (count($handstack) > 0) {
            $ghandstack = array_values($handstack);
            foreach ($ghandstack as $k => $val) {
                $qcards = $k;
            }
        }

        //0->5=> 6 cards
        if ($qcards < 5) {
            $qcards = 4 - $qcards;
            $this->gameStackReplenish($columnName, $qcards);
        }//echo $qcards;
    }

    /*
     * just adds Cards to hand Stack 
     * from the game stack 
     * 
     * @param string $columnName 
     * @param array $cards
     */

    private function addHandStack($columnName, $cards) {
        // echo "$cards";
        $gamblerstack = $this->GetData($columnName, "ar");

        // add this card to hand stack
        $newstack = json_encode(array_merge($gamblerstack, (array) $cards));
        //prepares string for sql update

        $newstack = $this->jsonFormated($newstack);

        $this->updateColums($columnName, $newstack);
    }

    /*
     * This function get 'master card' from the 'mastersuite' column,
     * return string. 
     * The data will passed to the game's table
     * 
     * @return string $this->mastersuit
     */

    private function getMasterSuit() {
        $this->mastersuit = $this->GetData("mastersuit", "");

        return $this->mastersuit;
    }

    /*
     * This function checks 'min' master suit card from the both players, 
     * also calls min_mode () function, 
     * analyzes the cards rank,
     * from the "mixed" strings array - (numbers and words) 
     * creates the integer array, 
     * converts from the 'string' to 'integer' 
     * checks master's cards  quantity
     * 
     * @param int $var
     * @return int $minval
     * 
     */

    private function minMaster($var) {

        if ($var == 0) {
            $checkarr = $this->GetData("userarray", "ar");
        } else {
            $checkarr = $this->GetData("opponentarray", "ar");
        }

        $str = $this->GetData("mastersuit", "");

        $minArr = array();

        $boo = str_replace((string) ((int) $str), "", $str);

        foreach ($checkarr as $val) {
            // if (strpbrk($val, $str)) { ? :(
            if ($boo == (str_replace((string) ((int) $val), "", $val))) {
                $minArr [] = (int) $val;
            }
        }

        $minval = $this->min_mod($minArr);

        return (int) $minval;
    }

    /*
     * This function checks the min value in the integer array, 
     * replaced '((min)function from PHP doc) that contains bugs, 
     * @param array $args - it is  integer array
     * @return int $min the lowests card range 
     */

    private function min_mod($args) {
        if (!count($args))
            return false;
        else {
            $min = false;
            foreach ($args as $value) {
                if (is_numeric($value)) {
                    $curval = floatval($value);
                    if ($curval < $min || $min === false)
                        $min = $curval;
                }
            }
        }

        return $min;
    }

    /*
     * get opponent array from Db
     * need for manipulation compares,
     * adds or removes
     *  
     */

    private function getOpponentCards() {
        return $this->GetData("opponentarray", "ar");
    }

    /*
     * gets user card  from db
     * need for manipulation compares,
     * @return array  
     * */

    private function getPlayerCards() {
        return $this->GetData("userarray", "ar");
    }

    /*
     * prepare the string for json_decode
     * @param string $data
     * @return string 
     */

    private function jsonFormated($data) {
        if (!empty($data)) {
            $data = preg_replace('#("[0-9]":)*#', '', $data);
            $data = preg_replace('/}/', ']', $data, 1);
            $data = preg_replace('/{/', '[', $data, 1);
            $data = addslashes($data);
            return $data;
        }
    }

    /*
     * call opponent array
     * checks from what card will atacks
     * @return string $mixOppcards lowes card from hend stack json encoded
     */

    private function opponenLowestCard() {
        $opparr = $this->getOpponentCards();
        // get Master suit array, coverts to string
        $str = $this->GetData("mastersuit", "");

        $oppNotsuitArr = array();
        $mixOppcards = array();
        $boo = str_replace((string) ((int) $str), "", $str);

        foreach ($opparr as $val) {

            if ($boo != (str_replace((string) ((int) $val), "", $val))) {

                $oppNotsuitArr[] = (int) $val;
            }
        }
        //lowest rank not "Master Suit" card of opponent array
        $minval = $this->min_mod($oppNotsuitArr);

        //takes lowes rank from aray
        foreach ($opparr as $k => $val) {

            if ($boo != (str_replace((string) ((int) $val), "", $val))) {
                if ($minval == (int) $val) {
                    $mixOppcards[] = $val;
                }
            }
        }
        $moo = $mixOppcards;
        if (empty($mixOppcards)) {

            foreach ($opparr as $val) {

                if ($boo == (str_replace((string) ((int) $val), "", $val))) {

                    $oppNotsuitArr[] = (int) $val;
                }
            }
            //lowest rank not "Master Suit" card of opponent array
            $minval = $this->min_mod($oppNotsuitArr);
            foreach ($opparr as $k => $val) {

                if ($boo == (str_replace((string) ((int) $val), "", $val))) {
                    if ($minval == (int) $val) {
                        $mixOppcards[] = $val;
                    }
                }
            }
        }
        // print_r(array_slice($mixOppcards, 0, 1));


        return json_encode($mixOppcards);

        //  return implode($mixOppcards);
        //return $mixOppcards;
        //print_r(array_slice($mixOppcards, 0, 1));
    }

    /*
     * function checks for the existiong opponent card,
     * the same rank
     * @paramm string $cards
     * @returns array $array the cards with same runk  
     */

    private function rankChecking($card) {
        $cint = 0;
        $cstr = "";
        if (is_string($card)) {
            $cint = (int) $card;
        } else {
            $cint = (int) implode($card);
        }
        $cstr = (string) $cint;
        $oparr = $this->getOpponentCards();

        $array = array();

        foreach ($oparr as $k => $val) {

            if ($cint == (int) $val) {
                $array[] = $val;
            }
        }
        return $array;
    }

    /*
     * remove one card from opponent or user
     * minus one card from array
     * 
     * @param  string     $columnName
     * @param array $someCard
     */

    private function handStackCardsMinus($columnName, $someCard) {
        //$lovestCard = $this->lowesOpponentCard();
        //removes 'lovest card' element from an array
        if (!is_string($columnName)) {
            $columnName = "opponentarray";
        }
        $array = array();
        if ($columnName === "userarray") {
            $array = $this->getPlayerCards();
        } else {
            $array = $this->getOpponentCards();
        }

        if (($key = array_search($someCard, (array) $array)) !== false) {
            unset($array[$key]);
        }

        $data = json_encode($array);
        //removes key from json array
        $data = $this->jsonFormated($data);
        $this->updateColums($columnName, $data);
    }

    /*
     * plus some cards if acsepts cards
     * this adds card from the attacker
     * not from game stack
     */

    private function pickupCardsOpponent($someCard) {

        //add one card element from the stack
        //$some shuld be string 
        $array = $this->getOpponentCards();
        $newarray = array_push($array, (string) $someCard);
        $newarray = addslashes($newarray);
        $this->updateColums('opponentarray', $newarray, "ar");
        //return $array;
    }

    private function pickupCardsPlayer($someCard) {
        //pivate funct no access to page    
        // $someCard = $_POST ['addcard'];
        // 
        // need valida to empty :) 
        //add one card element from the stack      
        $array = $this->getPlayerCards();
        array_push($array, $someCard);
        //  print_r($array);
        $boo = json_encode($array);

        // echo "$boo";
        $boo = addslashes($boo);
        $this->updateColums('userarray', $boo, "ar");


        /*
          //removs one or more cards from hand stack OPPONENT
          $this->handStackCardsMinus($someCard, "op");
          //checking qty cards
          $numb = $this->countsHandStack('opponentarray');
          //update hand stask opponent from main stack
          $newhanscard = $this->gameStackReplenish($numb);
          $this->addHandStack('opponentarray', $newhanscard); */

        //return $array;
    }

// will do late
    private function gameMesages($var) {
        $str = "";
        switch ($var) {
            case 1 :
                $str = "mesage1";
                break;
            case 2 :
                $str = "mesage1";
                break;
            case 3 :
                $str = "mesage1";
                break;
            case 4 :
                $str = "mesage1";
                break;
        }
    }

    /*
     * defence analyzer 
     * chech runk of attacker card
     * return the card bigests runk then attacker  if exist
     * if not - beat by less 'master card'
     * if can't pickup the all the cards and add to hands stack
     *
     * @param   string $defenderid  
     * @param   string $attackercard
     * @return  string $defenderscard
     */

    private function defenceAnalyzer($defenderid, $attackercard) {
        $defcard = "";
        //no direct acsess to page  
        // will removes for two players debugin
        $defenderid = 'opponentarray'; //who play stat for debug
        //$defcards = $defender;
        if ($defenderid === "opponentarray") {
            $defenderstack = $this->getOpponentCards();
        } else {
            $defenderstack = $this->getPlayerCards();
        }
        //needs for checking defenders cards
        //if the $attackercards array needs to be converted to string
        //one by one
        //bettr just gets string 
        $suit = str_replace((string) ((int) $attackercard), "", $attackercard);
        $defarray = array();
        foreach ($defenderstack as $val) {
            if ($suit == (str_replace((string) ((int) $val), "", $val))) {

                if ((int) $attackercard < (int) $val) {
                    $defarray[] = (int) $val;
                }
            }
        }
        $defendersuit = array();
        if (!empty($defarray)) {
            /* @var $mindefcard int */
            $mindefcard = $this->min_mod($defarray);
            /* @var $val string */
            foreach ($defenderstack as $val) {
                /* @var $suit string */
                if ($suit == (str_replace((string) ((int) $val), "", $val))) {
                    /* @var $defcard int i made tricks move $val  to int */
                    if ($mindefcard == (int) $val) {
                        $defcard = (string) $val;
                    }
                }
            }
        } else {
            $masterarray = array();
            // very bad needs to move colls this function to the game table
            $msuit = $this->getMasterSuit();
            //$msuit = $this->GetData("mastersuit", "");
            $msuit = str_replace((string) ((int) $msuit), "", $msuit);
            /* @var $val string */
            foreach ($defenderstack as $val) {
                /* @var $msuit string */
                if ($msuit == (str_replace((string) ((int) $val), "", $val))) {
                    /* @var $defcard int i made tricks move $val  to int */
                    $masterarray[] = $val;
                }
            }
            /* @var $defcard  int */
            $defcardmin = $this->minMaster(2);
            foreach ($masterarray as $val) {
                /* @var $defcard int i made tricks move $val  to int */
                if ($defcardmin == (int) $val) {
                    $defcard = (string) $val;
                }
            }
        }
        /* @var $defcard string */
        return $defcard;
        //call function messager
    }

    /*
     * PC Attack function 
     * return attaker card
     *  
     */

    private function pcattackAnaliser() {
        // Attack
        // 1. call functoin to analize to attack smolest card
        $attackercard = $this->opponenLowestCard();
        // 2.delivery this card to game table
        if (empty($attackercard)) {
            $attackercard = $this->minMaster(2);
        }
        $defcard = $_POST ['defcard'] . ";";
        //analize defender cards  
        //and         
        //adds same rank cards to game table  
        $newattackcard = $this->rankChecking($defcard);
        // 5.Call message function(not now, will do)
        // 6.remove atakers card from hand stack
        $numb = $this->countsHandStack('opponentarray');

        return $newattackcard;
    }

    /*
     * get data from  page data  and updates the action and gflag columns
     * 
     * eveents: attack start, attack stop, defence, pickup, collect
     */

    public function eventsAjax() {
        // echo json_encode($arr);  
        //////////////////////////////    
        // $cardid moves to json format 
        $action = $_POST ['action'];
        $cardid = $_POST ['ids'];
        $cardid = rtrim($cardid, ',""');
        //$cardid = "[\"" . $cardid . "\"]";
        //$cardidceck = preg_replace('/\[\"|\"]/', '', $cardid);
        $cardidceck = '"' . $cardid . '"';

        if (!empty($action)) {
            if (!empty($cardidceck)) {
                // adds the cards in json format
                $this->updateColums('gflag', addslashes("$cardidceck"));
            } else {
                //EMPTY  DATA
                $this->updateColums('gflag', "");
            }
            $this->updateColums('action', $action);
        }
    }

    /*
     * checks for the action fild  if empty 
     * 
     * @return action strin status
     */

    private function gameAction() {

        return $this->GetData('action', "");
    }

    /*
     * this function is used for the debugging, 
     * will override letter
     * @param global string $fenrty
     * @param string $action post from page  $_POST ['action'];
     * @param string $card post from page  $_POST ['id']
     * @return string
     */

    public function gameTable() {
        ///first time run

        $action = $this->gameAction();
        if (empty($action)) {
            $this->firstTimeRun();
            echo '["start"]';
        }
        switch ($action) {
            //START
            case "start":
                $action = $this->starCompetition();
                $coountopccards = count($this->getOpponentCards());
                $attackcards = preg_replace('/\[\"|\"]/', '', $this->opponenLowestCard());

                $usercards = json_encode($this->getPlayerCards());
                $usercards = preg_replace('/\[\"|\"]/', '', $usercards);
                $ucards = '{"usercard":"'
                        . preg_replace('/,/', '},{"usercard":', $usercards)
                        . '"}';
                $massuit = $this->getMasterSuit();
                if ($action !== "defence") {
                    $attackcards = "1";
                }
                echo '[{"opponqty":"' . $coountopccards
                . '","opponentattack":"' . $attackcards . '", "action":"' . $action
                . '","mastercard":"' . $massuit . '"},' . $ucards . ']';
                break;
            ///done  ////////USER  DEFENCE
            case "defence":
                $coountopccards = count($this->getOpponentCards());
                $attackcards = $this->opponenLowestCard();
                $usercards = json_encode($this->getPlayerCards());
                $massuit = $this->getMasterSuit();
                ///prepares string 4 Json format
                $usercards = preg_replace('/\[\"|\"]/', '', $usercards);
                $attackcards = preg_replace('/\[\"|\"]/', '', $attackcards);
                $ucards = '{"usercard":"'
                        . preg_replace('/,/', '},{"usercard":', $usercards) . '"}';
                echo '[{"opponqty":"'
                . $coountopccards . '","opponentattack":" ' .
                $attackcards . '","action":"'
                . $action . '","mastercard":" ' . $massuit . '"},'
                . $ucards . '
                 ]';
                break;
            // UATACK
            case "uattack":
                $defenderid = "opponentarray";
                $attackercard = $this->GetData("gflag", "ar");
                $opponentcards = $this->defenceAnalyzer($defenderid, $attackercard);
                $coountopccards = (int) count($this->getOpponentCards()) - 1;
                $attackcards = preg_replace('/\[\"|\"]/', '', $this->opponenLowestCard());

                $usercards = json_encode($this->getPlayerCards());
                $usercards = preg_replace('/\[\"|\"]/', '', $usercards);
                $ucards = '{"usercard":"'
                        . preg_replace('/,/', '},{"usercard":', $usercards)
                        . '"}';
                $massuit = $this->getMasterSuit();

                echo '[{"opponqty":"' . $coountopccards
                . '","opponentattack":"' . $opponentcards . '", "action":"' . $action
                . '","mastercard":"' . $massuit . '"},' . $ucards . ']';

                break;
            /////////// USER ATACK ///////////////  
            //get attackers cards
            // analizes the attackers cards and return
            // sasme suit with hier runk or muster suit card
            // the flag attack will chenge to defence
            //if cant defence picup the cards and flag still the same ATACK
            case "attack":
                $defenderid = "opponentarray";
                $attackercard = $this->GetData("gflag", "ar");
                $this->defenceAnalyzer($defenderid, $attackercard);
                $coountopccards = count($this->getOpponentCards());
                $attackcards = preg_replace('/\[\"|\"]/', '', $this->opponenLowestCard());

                $usercards = json_encode($this->getPlayerCards());
                $usercards = preg_replace('/\[\"|\"]/', '', $usercards);
                $ucards = '{"usercard":"'
                        . preg_replace('/,/', '},{"usercard":', $usercards)
                        . '"}';
                $massuit = $this->getMasterSuit();

                echo '[{"opponqty":"' . $coountopccards
                . '","opponentattack":"", "action":"' . $action
                . '","mastercard":"' . $massuit . '"},' . $ucards . ']';

                break;
            // PICKUP
            case "pickup":
                echo '["pickup"]';

                break;
        }



        //////////PICKUP
        if ($action === "pickup") {
            echo '["pickup"]';
        }
    }

    public
            function starCompetition() {
        $actio = "";

        if (((int) $this->minMaster(0) > (int) $this->minMaster(2)) or (int) $this->minMaster(0) == 0) {
            ///user starts attack
            // $this->updateColums('action', "attack");
            return $actio = "uattack";
        } else {
            //pc starts attack
            //     $this->updateColums('action', "defence");
            return $actio = "defence";
        }
    }

}

